package com.dhms.vostok1.network

import androidx.annotation.Nullable
import com.dhms.vostok1.data.abnormals.FaultState
import com.dhms.vostok1.data.abnormals.SpotSource
import com.dhms.vostok1.data.message_center.MessageCenterType
import com.dhms.vostok1.data.spot_patrol.AttachmentType
import com.dhms.vostok1.data.spot_patrol.PlanType
import com.dhms.vostok1.data.spot_patrol.TaskStatus
import com.dhms.vostok1.data.todo.ToDoBizType
import com.squareup.moshi.*
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import io.realm.kotlin.ext.realmListOf
import io.realm.kotlin.types.RealmList
import java.io.IOException


object MoshiObject {
    /**
     * moshi object for the retrofit object
     */
    val moshi: Moshi = Moshi.Builder()
        .add(TaskStatusAdapter())
        .add(AttachmentTypeAdapter())
        .add(PlanTypeAdapter())
        .add(FaultStateAdapter())
        .add(SpotSourceTypeAdapter())
        .add(MessageCenterTypeAdapter())
        .add(RealmListJsonAdapterFactory())
        .add(KotlinJsonAdapterFactory())
        .add(ToDoBizTypeAdapter())
        .build()

    val jsonAdapter: JsonAdapter<Map<String, Any>> = moshi.adapter(
        Types.newParameterizedType(
            MutableMap::class.java,
            String::class.java,
            Any::class.java
        )
    )

    val jsonAdapterToMapString: JsonAdapter<Map<String, String>> = moshi.adapter(
        Types.newParameterizedType(
            MutableMap::class.java,
            String::class.java,
            String::class.java
        )
    )

    val jsonAdapterToMapAny: JsonAdapter<Map<String, Any>> = moshi.adapter(
        Types.newParameterizedType(
            MutableMap::class.java,
            String::class.java,
            Any::class.java
        )
    )
}

class AttachmentTypeAdapter {
    @ToJson
    fun toJson(type: AttachmentType): Int = type.code

    @FromJson
    fun fromJson(value: String): AttachmentType = AttachmentType.fromInt(value.toInt())
}


class PlanTypeAdapter {
    @ToJson
    fun toJson(type: PlanType): Int = type.code

    @FromJson
    fun fromJson(value: String): PlanType = PlanType.fromInt(value.toInt())
}

class TaskStatusAdapter {
    @ToJson
    fun toJson(type: TaskStatus): Int = type.code

    @FromJson
    fun fromJson(value: String): TaskStatus = TaskStatus.fromInt(value.toInt())
}

class SpotSourceTypeAdapter {
    @ToJson
    fun toJson(type: SpotSource): String = type.value

    @FromJson
    fun fromJson(value: String): SpotSource = SpotSource.fromString(value)
}

class FaultStateAdapter {
    @ToJson
    fun toJson(type: FaultState): String = type.value

    @FromJson
    fun fromJson(value: String): FaultState = FaultState.fromString(value)
}

class MessageCenterTypeAdapter {
    @ToJson
    fun toJson(type: MessageCenterType): String = type.value

    @FromJson
    fun fromJson(value: String): MessageCenterType = MessageCenterType.fromString(value)
}

class RealmListAdapter<T : Any?>(private val elementAdapter: JsonAdapter<T>) :
    JsonAdapter<RealmList<T>?>() {
    @Throws(IOException::class)

    @Nullable
    override fun fromJson(reader: JsonReader): RealmList<T> {
        val result: RealmList<T> = realmListOf()
        reader.beginArray()
        while (reader.hasNext()) {
            elementAdapter.fromJson(reader)?.let { result.add(it) }
        }
        reader.endArray()
        return result
    }

    override fun toJson(writer: JsonWriter, value: RealmList<T>?) {
        writer.beginArray()
        if (value != null) {
            for (element in value) {
                elementAdapter.toJson(writer, element)
            }
        }
        writer.endArray()
    }
}

class ToDoBizTypeAdapter {
    @ToJson
    fun toJson(type: ToDoBizType): Int = type.value

    @FromJson
    fun fromJson(value: Int): ToDoBizType = ToDoBizType.fromInt(value)
}